import base64
import hashlib
import hmac
import json
import time
import logging
import requests
from _sha1 import sha1
from datetime import datetime

from utils.common.db_handle import route_del, get_mac_info, create_route, check_mac_is_exist
from utils.common.encryption import EnCryPt

logger = logging.getLogger(__name__)


def create_timestamp():
    """
    创建时间戳
    :return:
    """
    times = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    timearray = time.strptime(times, "%Y-%m-%d %H:%M:%S")
    timestamp = str(int(time.mktime(timearray)))
    return timestamp


def get_sign(before):
    """
    签名
    """

    before = bytes(before, encoding="utf8")
    salt = EnCryPt().debase64(b'dnBuY24uMTIzJmFzZGY=')
    befor_url = hmac.new(bytes(salt, encoding='utf-8'), before, sha1).digest()
    sign = base64.b64encode(befor_url)
    sign = str(sign, encoding="utf-8")
    return sign


def reuturn_headers():
    # 请求头
    headers = {
        'Content-Type': "application/x-www-form-urlencoded",
        'cache-control': "no-cache",
        'Postman-Token': "d2d27edd-6795-45be-a1ef-d4cd749f79c4"
    }
    return headers


class SendRequest:
    """发送请求"""

    def __init__(self):
        self.headers = reuturn_headers()

    def get(self, url):
        """发送请求"""
        try:
            r = requests.get(url, headers=self.headers, timeout=30)
        except Exception as e:
            print('get 请求出错：%s' % e)
            logger.error('get 发送请求错误：%s', e)
            r = None

        logger.info('get 请求，状态码：%s，响应：%s', r.status_code, r.text)

        return r

    def post(self, url, data):
        """发送请求"""
        try:
            r = requests.post(url, data=data, headers=self.headers, timeout=30)
        except Exception as e:
            logger.error('post 发送请求错误：%s', e)
            print('post 请求出错：%s' % e)
            r = None

        logger.info('post 请求，状态码：%s，响应：%s', r.status_code, r.text)
        return r

    def res_handle(self, r):
        """处理响应"""
        if r:
            if r.status_code == 200:
                content = r.text
                if self.is_json(content):
                    if r.json().get('code') == 0:
                        ret = r.json()
                    else:
                        ret = None
                else:
                    ret = None
            else:
                ret = None
        else:
            ret = None

        return ret

    def is_json(self, content):
        """检查返回值是否是 json 格式"""
        try:
            json_object = json.loads(content)
        except ValueError as e:
            return False
        return True


class RouteSend:

    def __init__(self):
        self.sr = SendRequest()

    def generate_url(self, mac, hmac):
        """构造 URL"""
        timestamp = create_timestamp()
        before_url = "get_device_info?AccessId=vpncnadmin&hmac=" + hmac + "&macaddr=" + mac + "&timestamp=" + timestamp
        sign = get_sign(before_url)
        url = "http://rcloud.vpn.cn:8088/api/get_device_info?AccessId=vpncnadmin&hmac=" + hmac + "&macaddr=" + mac + "&timestamp=" \
              + timestamp + "&sign=" + sign

        return url

    def check_mac(self, user: object, mac: str, hmac: str):
        """
        检查路由器
        :param user: 用户对象
        :param mac: 路由器 Mac 地址
        :param hmac: hmac 信息
        :return:
        """
        url = self.generate_url(mac, hmac)
        resp = self.sr.get(url)
        # print('resp', resp.status_code, resp.text)
        result = self.sr.res_handle(resp)

        # print('check_mac====>', result)

        return result

    def mac_resp_handle(self, check_mac_result, mac, hmac, user):
        """check mac 结果处理"""
        # 请求成功
        if check_mac_result:
            # 检查路由器是否在线
            if check_mac_result.get("data").get("connection") == "disconnected":
                ret = {'code': 10003, 'msg': '路由器离线或不存在'}  # 路由不在线或不存在
            else:
                # 若在线，检查当前路由与当前用户的关系
                ret = self.check_mac_user(check_mac_result, mac, hmac, user)
        else:
            # 请求失败，状态码，非 0
            ret = {'code': 10014, 'msg': '服务器内部错误'}

        return ret

    def check_mac_user(self, content, mac, hmac, user):
        """检查Mac与当前用户的关系"""
        ret = {'code': 0, 'msg': '请求成功'}
        # 检查路由器与当前用户的状态，已绑定其他用户，数据库中不存在，属于当前用户
        mac_status = check_mac_is_exist(mac, user)
        logger.info('检查路由器状态：%s' % mac_status)

        # 该 Mac 已绑定其他用户
        if mac_status['code'] == 10005:
            ret = {'code': 10005, 'msg': mac_status['msg']}
        elif (mac_status['code'] == 10006) and (content.get("data").get('enabled') == 0):
            # 该 Mac 属于当前用户，但是路由器状态已恢复出厂设置，需要更新数据库，回收 tos_list
            route_del(mac)
            ret = {'code': 0, 'msg': '该路由器已恢复出厂设置'}
        elif mac_status['code'] == 10007:
            # 若 Mac 不存在，则写入数据库
            self.build_dic(mac, hmac, user.id)
            ret = {'code': 0, 'msg': mac_status['msg']}

        return ret

    def build_dic(self, mac, hmac, user_id):
        """构造字典，将路由存入数据库中"""
        save_dic = {
            'name': mac,
            'mac_addr': mac,
            'hmac_addr': hmac,
            'user_id': str(user_id),
            'bind_time': None,
            'tos_list': list(range(200)),
            'server_addr': '',
            'tunnel': '0'
        }

        # 创建路由
        create_route(save_dic)


class RouteBind:
    """绑定服务器"""

    def __init__(self):
        self.sr = SendRequest()

    def generate_url(self, mac, hmac, server, proto):
        """构造 URL"""
        timestamp = create_timestamp()
        before_url = "bind_server?AccessId=vpncnadmin&hmac=" + hmac + "&macaddr=" + mac + "&proto=" + proto + "&server=" + \
                     server + "&timestamp=" + timestamp
        sign = get_sign(before_url)
        url = "http://rcloud.vpn.cn:8088/api/bind_server?AccessId=vpncnadmin&hmac=" + hmac + "&macaddr=" + mac + "&proto=" \
              + proto + "&server=" + server + "&timestamp=" + timestamp + "&sign=" + sign

        return url

    def route_bind(self, mac, hmac, server_addr, tunnel):
        """
        路由器绑定服务器
        :param mac: 路由器 mac
        :param hmac: hmac
        :param server_addr: 服务器地址
        :param tunnel: 通道
        :return:
        """
        url = self.generate_url(mac, hmac, server_addr, tunnel)
        resp = self.sr.get(url)
        result = self.sr.res_handle(resp)

        logger.info('%s 绑定服务器：%s，状态：%s', mac, server_addr, result)

        if result:
            ret = {'code': 0, 'msg': '绑定成功'}
        else:
            ret = {'code': 10009, 'msg': '服务器绑定失败'}

        return ret


class RouteUnBind:
    """解绑服务器"""

    def __init__(self):
        self.sr = SendRequest()

    def generate_url(self, mac, hmac):
        """构造 URL"""
        timestamp = create_timestamp()
        before_url = "unbind_server?AccessId=vpncnadmin&hmac=" + hmac + "&macaddr=" + mac + "&timestamp=" + timestamp
        sign = get_sign(before_url)
        url = "http://rcloud.vpn.cn:8088/api/unbind_server?AccessId=vpncnadmin&hmac=" + hmac + "&macaddr=" + mac + \
              "&timestamp=" + timestamp + "&sign=" + sign

        return url

    def route_unbind(self, mac, hmac):
        """
        路由器解除绑定服务器
        :param mac: 路由器 mac
        :param hmac: hmac
        :param server_addr: 服务器地址
        :param tunnel: 通道
        :return:
        """
        url = self.generate_url(mac, hmac)
        resp = self.sr.get(url)
        result = self.sr.res_handle(resp)
        logger.info('%s 解绑：%s', mac, result)

        if result:
            ret = {'code': 0, 'msg': '解绑成功'}
        else:
            ret = {'code': 10010, 'msg': '解绑失败'}

        return ret


class QueryDeviceIp:
    """查询设备公网IP"""

    def __init__(self):
        pass

    def handle(self, device_list: list):
        """判断设备是否已启用通道"""
        for device in device_list:
            if device["tunnel_status"] == "启用":
                pass

    def get_public_ip(self):
        """获取公网 IP"""
        pass
        # 获取时间戳
        # timestamp = create_timestamp()
        # data_dic = '{"peers": ["%s"]}' % peer
        #
        # hl = hashlib.md5()
        # hl.update(data_dic.encode("utf8"))
        # body = hl.hexdigest()
        #
        # before = "get_tunnel_info_test?AccessId=vpncnadmin&body=%s&timestamp=%s" % (body, timestamp)
        # sign = get_sign(before)
        #
        # url = "http://p.rusell.top:8088/api/get_tunnel_info_test?AccessId=vpncnadmin&body=%s&timestamp=%s&sign=%s" % (
        # body, timestamp, sign)
        #
        # # "data":{"TtGJiuZ54aogJRrHc3AOUCm15yR5tQ+PW6ImBcFoVyA=":{"status":"peer online","ip":"106.111.69.201"}}
        # try:
        #     r = requests.post(url, data=data_dic, headers=reuturn_headers(), timeout=30)
        #     print('>>?', r.status_code, r.text, url)
        #
        #     logger.info("获取公网 ip返回值:{}".format(r.text))
        #
        #     if r.status_code == 200:
        #         data = json.loads(r.text)
        #         if data['code'] == 0:
        #             return 'OK', data.get("data")
        #         elif data['code'] == 109:
        #             return 'OFFLINE', 'peer 不在线'
        #         elif data['code'] == 101:
        #             return 'TimeOut', '查询超时'
        #         else:
        #             return 'NO', 'NO'
        #     else:
        #         return "ERROR", 'ERROR'
        # except Exception as e:
        #     logger.error('获取公网IP出现错误：%s' % e)
        #     return 'NO', 'NO'


class RouteDetail:
    """查询路由器详情"""

    def __init__(self):
        self.sr = SendRequest()

    def generate_data(self, data):
        """构造 payload"""

        return str(data).replace("'", '"').replace(" ", '')

    def generate_url(self, mac_addr, hmac_addr, data):
        """构造 URL"""
        timestamp = create_timestamp()
        h1 = hashlib.md5()
        h1.update(str(json.dumps(data).replace("'", '"').replace(" ", "")).encode("utf8"))
        body = h1.hexdigest()

        before_url = "get_mac_info?AccessId=vpncnadmin&body={}&hmac={}&macaddr={}&timestamp={}". \
            format(body, hmac_addr, mac_addr, timestamp)
        sign = get_sign(before_url)
        url = "http://rcloud.vpn.cn:8088/api/get_mac_info?AccessId=vpncnadmin&body={}&hmac={}&macaddr={}&timestamp={}&sign={}". \
            format(
            body, hmac_addr, mac_addr, timestamp, sign
        )

        return url

    def fetch(self, mac, hmac_addr, data):
        url = self.generate_url(mac, hmac_addr, data)
        data = self.generate_data(data)

        resp = self.sr.post(url, data)
        result = self.sr.res_handle(resp)

        print(resp)
        print('result', result)

        # logger.info('%s 解绑：%s', mac, result)

        if result:
            ret = {'code': 0, 'msg': '请求成功', "data": result.get('data')}
        else:
            ret = {'code': 10028, 'msg': '获取详情失败', "data": []}

        return ret


if __name__ == '__main__':
    rb = RouteBind()
    rub = RouteUnBind()
    rs = RouteSend()

    # mac_addr = '00156C000006'
    # hmac_addr = 'AmkjCDT5b8bYZz1OajAEOP8H/5U=8'
    # server_addr = 'raccess1.vpn.cn'
    # tunnel = 'TCP'
    #
    # rs.check_mac('rose', mac_addr, hmac_addr)

    # # rb.route_bind(mac_addr, hmac_addr, server_addr, tunnel)
    # rub.route_unbind(mac_addr, hmac_addr)
    #

    rd = RouteDetail()
    mac_addr = '000000000000'
    hmac_addr = 'xMTDxRwp28BSXIufaCQZXcllw/E='
    data = {"macaddr": ["00156C000018"]}
    rd.fetch(mac_addr, hmac_addr, data)
